package com.powernode.config;

import com.powernode.constant.RedisConstant;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
//开启缓存
@EnableCaching
public class RedisConfig {

    /**
     * redis操作模板的序列化器配置
     */
    @Bean
    public RedisTemplate<String,?> redisTemplate(RedisConnectionFactory factory){

        RedisTemplate<String,?> redisTemplate = new RedisTemplate<>();

        // 设置redis数据库连接工厂
        redisTemplate.setConnectionFactory(factory);
        // 设置key序列化器为String
        redisTemplate.setKeySerializer(RedisSerializer.string());
        // 设置hashKey序列化器为String
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // 设置value序列化器为json
        redisTemplate.setValueSerializer(RedisSerializer.json());
        // 设置hashValue序列化器为json
        redisTemplate.setHashValueSerializer(RedisSerializer.json());

        return redisTemplate;
    }

    /**
     * 缓存管理器的配置
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {

        //缓存初始化配置放入Map<String,RedisCacheConfiguration>集合中,其中key是缓存key的名称
        Map<String, RedisCacheConfiguration> cacheConfig = new HashMap<>();
        //key是缓存key的名称， value是过期时间的配置，Duration.ZERO表示永不过期
        cacheConfig.put(RedisConstant.KEY_PRODUCT,redisCacheConfiguration().entryTtl(Duration.ofMinutes(10)));
        cacheConfig.put(RedisConstant.KEY_INDEX_CATEGORY,redisCacheConfiguration().entryTtl(Duration.ZERO));
        cacheConfig.put(RedisConstant.KEY_AUTH_LOGIN_CODE,redisCacheConfiguration().entryTtl(Duration.ofMinutes(1)));
        return RedisCacheManager.builder(factory)
                //缓存默认配置
                .cacheDefaults(redisCacheConfiguration())
                //缓存初始化配置
                .withInitialCacheConfigurations(cacheConfig)
                .transactionAware()
                .build();
    }

    private RedisCacheConfiguration redisCacheConfiguration(){
        //springCache默认配置了允许缓存null值，在RedisCacheConfiguration类的构造方法中
        //当查询一个不存在的key时redis会缓存一个null值，避免缓存穿透
        return RedisCacheConfiguration.defaultCacheConfig()
                //配置缓存key的前缀
                .computePrefixWith(cacheName -> cacheName + ":")
                //key序列化器，字符串序列化器
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                //value序列化器，json序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                //设置全局缓存有效期
                .entryTtl(Duration.ofMinutes(20));
                //设置不缓存null值，当大量请求访问一个不存在的key时，会一直访问数据库，造成缓存穿透
                //.disableCachingNullValues();
    }
}
